/*
 * Copyright 2009 BioTeam Inc
 * 
 * Licensed under License GNU LESSER GENERAL PUBLIC LICENSE version 3.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 * 
 * http://www.gnu.org/copyleft/lesser.html
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package net.bioteam.appweb.gwt.apps.client.datatree;

import net.bioteam.appweb.gwt.apps.client.StaticHolder;
import net.bioteam.appweb.gwt.apps.client.Util.Util;
import net.bioteam.appweb.gwt.apps.clientandserver.Constant;

import com.smartgwt.client.data.DSCallback;
import com.smartgwt.client.data.DSRequest;
import com.smartgwt.client.data.DSResponse;
import com.smartgwt.client.rpc.RPCResponse;
import com.smartgwt.client.types.EnterKeyEditAction;
import com.smartgwt.client.types.ListGridEditEvent;
import com.smartgwt.client.types.ListGridFieldType;
import com.smartgwt.client.util.BooleanCallback;
import com.smartgwt.client.util.SC;
import com.smartgwt.client.widgets.Canvas;
import com.smartgwt.client.widgets.events.DragStartEvent;
import com.smartgwt.client.widgets.events.DragStartHandler;
import com.smartgwt.client.widgets.events.DrawEvent;
import com.smartgwt.client.widgets.events.DrawHandler;
import com.smartgwt.client.widgets.form.validator.CustomValidator;
import com.smartgwt.client.widgets.form.validator.Validator;
import com.smartgwt.client.widgets.grid.ListGridRecord;
import com.smartgwt.client.widgets.menu.Menu;
import com.smartgwt.client.widgets.menu.MenuItem;
import com.smartgwt.client.widgets.menu.MenuItemIfFunction;
import com.smartgwt.client.widgets.menu.events.ClickHandler;
import com.smartgwt.client.widgets.menu.events.MenuItemClickEvent;
import com.smartgwt.client.widgets.tree.Tree;
import com.smartgwt.client.widgets.tree.TreeGrid;
import com.smartgwt.client.widgets.tree.TreeGridField;
import com.smartgwt.client.widgets.tree.TreeNode;
import com.smartgwt.client.widgets.tree.events.FolderDropEvent;
import com.smartgwt.client.widgets.tree.events.FolderDropHandler;
import com.smartgwt.client.widgets.tree.events.LeafClickEvent;
import com.smartgwt.client.widgets.tree.events.LeafClickHandler;

public class DataTreeGrid extends TreeGrid
{
	public static final int publicNodeID = 1;
	public static final int jobNodeID = 3;
	public static final int dataNodeID = 2;
	public static final String publicNodeName = "Shared";
	public static final String jobNodeName = "My Jobs";
	public static final String dataNodeName = "My Data";

	public static enum ViewState
	{
		USER, SELECT, JOB_TRANSFER
	};

	ViewState viewState;

	public DataTreeGrid()
	{
		this(ViewState.USER);
	}

	public String jobFileSrcPath;
	public DataTreeGrid(ViewState state)
	{
		super();
		viewState = state;
		setWidth(300);
		setHeight100();

		setShowRoot(false);
		// ----------edge

//		setShowEdges(true);
//		setBorder("opx");
//		setBodyStyleName("normal");

		setAnimateFolders(false);
		setShowHeader(false);

		if (viewState == ViewState.USER || viewState == ViewState.JOB_TRANSFER)
		{
			// ------edting/rename setting.
			setCanEdit(true);
			setEditEvent(ListGridEditEvent.DOUBLECLICK);
			setEnterKeyEditAction(EnterKeyEditAction.DONE);
			setAutoSaveEdits(true);
			setModalEditing(true);

			// drag/drop
			setCanReorderRecords(false);
			setCanReparentNodes(true);
			setCanAcceptDroppedRecords(true);
			setCanDragRecordsOut(false);
			setCanDropOnLeaves(false);

			addDragStartHandler(new DragStartHandler()
			{

				public void onDragStart(DragStartEvent event)
				{
					jobFileSrcPath=null;
				}
			});
			//http://code.google.com/p/smartgwt/issues/detail?id=219
			addFolderDropHandler(new  FolderDropHandler(){

				public void onFolderDrop(FolderDropEvent event)
				{
					TreeNode destNode=event.getFolder();
					TreeNode srcNode=event.getNodes()[0];
					//Util.debugJSObject(srcNode.getJsObj(), "srcNode");
					 TreeNode newNode=new TreeNode();
					if (jobFileSrcPath!=null)
					{
						//drop from jobFiles
						newNode.setAttribute("_myjobpath", jobFileSrcPath);
						jobFileSrcPath=null;
						newNode.setAttribute("parentId", destNode.getAttribute("id"));
						DataTreeGrid.this.addData(newNode);
					} 
				}});
			
//			addDropHandler(new DropHandler(){
//			
//			 public void onDrop(DropEvent event)
//			 {
//				 TreeNode destNode=(TreeNode)DataTreeGrid.this.getRecord(DataTreeGrid.this.getEventRow());
//				 TreeNode newNode=new TreeNode();
//				if (jobFileSrcPath!=null)
//				{
//					//drop from jobFiles
//					newNode.setAttribute("_myjobpath", jobFileSrcPath);
//					jobFileSrcPath=null;
//					newNode.setAttribute("parentId", destNode.getAttribute("id"));
//					DataTreeGrid.this.addData(newNode);
//				} 
//			 }});
		}
	
		TreeNode[] roots = null;
		TreeNode dataNode = new TreeNode();
		dataNode.setAttribute("id", dataNodeID);
		dataNode.setAttribute("name", dataNodeName);
		dataNode.setAttribute("servername", Constant.data_name);
		dataNode.setAttribute("folder", true);
		if (viewState == ViewState.USER || viewState == ViewState.JOB_TRANSFER)
		{
			roots = new TreeNode[1];
			roots[0] = dataNode;
		} else
		{
			roots = new TreeNode[3];
			TreeNode publicNode = new TreeNode();
			publicNode.setAttribute("id", publicNodeID);
			publicNode.setAttribute("name", publicNodeName);
			publicNode.setAttribute("servername", Constant.server_file_public_name);
			publicNode.setAttribute("folder", true);
			roots[0] = publicNode;

			roots[1] = dataNode;

			TreeNode jobNode = new TreeNode();
			jobNode.setAttribute("id", jobNodeID);
			jobNode.setAttribute("name", jobNodeName);
			jobNode.setAttribute("servername", Constant.job_name);
			jobNode.setAttribute("folder", true);
			roots[2] = jobNode;
		}

		TreeGridField tf = new TreeGridField("name", "Data");
		if (viewState == ViewState.USER || viewState == ViewState.JOB_TRANSFER)
			tf.setCanEdit(true);
		tf.setCanToggle(false);
		tf.setCanSort(false);
		tf.setTreeField(true);
		tf.setType(ListGridFieldType.TEXT);

		Validator validator = new CustomValidator()
		{
			@Override
			protected boolean condition(Object value)
			{
				String str = value.toString();
				if (!str.matches("^[a-zA-Z].+"))
				{
					setErrorMessage("First character has to be a letter");
					return false;
				}
				if (str.indexOf('/') != -1 || str.indexOf('\\') != -1)
				{
					setErrorMessage("/ and \\ is not allowed in path");
					return false;
				}
				return true;
			}
		};
		tf.setValidators(validator);

		setFields(tf);
		setInitialData(roots);

		final DataTreeDataSource src = new DataTreeDataSource();
		setDataSource(src);
		src.treeGrid = this;
		setLoadDataOnDemand(true);

		// TODO http://forums.smartclient.com/showthread.php?t=4926
		// Can not setTree right now, has to use setInitialData
		addDrawHandler(new DrawHandler()
		{
			public void onDraw(DrawEvent event)
			{
				Tree tree = DataTreeGrid.this.getTree();
				tree.getRoot().setAttribute("servername", "");
				tree.setNameProperty("servername");
				tree.setPathDelim("/");
				tree.setIsFolderProperty("folder");
			}
		});

		if (viewState == ViewState.USER || viewState == ViewState.JOB_TRANSFER)
		{
		addLeafClickHandler(new LeafClickHandler(){

			public void onLeafClick(LeafClickEvent event)
			{
				TreeNode treeNode = event.getLeaf();
				String href = treeNode.getAttributeAsString("href");
				if (href != null)
				{
					Util.open(href);
				}
				
			}});
		}
		final Menu menu = new Menu();
		menu.setShowShadow(true);
		menu.setShadowDepth(10);

		final MenuItem reloadItem = new MenuItem("Reload");
		final MenuItem renameItem = new MenuItem("Rename");
		final MenuItem deleteItem = new MenuItem("Delete");
		final MenuItem copyItem = new MenuItem("Copy");
		final MenuItem folderItem = new MenuItem("New Folder");
		final MenuItem uploadItem = new MenuItem("Upload");
		final MenuItem viewItem = new MenuItem("view");
		final MenuItem zipItem = new MenuItem("Download as zip");

		// -----------------------deletion logic
		final BooleanCallback deleteCallback = new BooleanCallback()
		{

			public void execute(Boolean value)
			{
				if (value!=null && value)
				{
					DataTreeGrid.this.removeSelectedData();
				}
			}

		};

		deleteItem.addClickHandler(new ClickHandler()
		{

			public void onClick(MenuItemClickEvent event)
			{
				ListGridRecord[] nodes = DataTreeGrid.this.getSelection();
				if (nodes != null && nodes.length > 0)
					SC.confirm("Do you want to delete selected Folder/File?", deleteCallback);
			}
		});
		
		//http://code.google.com/p/smartgwt/issues/detail?id=186
		deleteItem.setEnableIfCondition(new MenuItemIfFunction()
		{

			public boolean execute(Canvas target, Menu menu, MenuItem item)
			{
				TreeNode node = (TreeNode) DataTreeGrid.this.getRecord(DataTreeGrid.this.getEventRow());
				return !node.getAttributeAsString("id").equals(String.valueOf(dataNodeID));
			}
		});

		// ------------------rename
		renameItem.addClickHandler(new ClickHandler()
		{

			public void onClick(MenuItemClickEvent event)
			{
				ListGridRecord record = DataTreeGrid.this.getSelectedRecord();
				int rowNum = DataTreeGrid.this.getRecordIndex(record);
				DataTreeGrid.this.startEditing(rowNum, 0, false);
			}
		});
		renameItem.setEnableIfCondition(new MenuItemIfFunction()
		{

			public boolean execute(Canvas target, Menu menu, MenuItem item)
			{
				TreeNode node = (TreeNode) DataTreeGrid.this.getRecord(DataTreeGrid.this.getEventRow());
				return !node.getAttributeAsString("id").equals(String.valueOf(dataNodeID));
			}
		});


		// -------------------copy
		copyItem.addClickHandler(new ClickHandler()
		{

			public void onClick(MenuItemClickEvent event)
			{
				final TreeNode record =(TreeNode) DataTreeGrid.this.getSelectedRecord();
				TreeNode node = new TreeNode();
				node.setAttribute("name", "copyof" + record.getAttribute("name"));
				node.setAttribute("servername", "copyof" + record.getAttribute("servername"));
				// node.setAttribute("_appcopy", true);
				node.setAttribute("_appoldname", record.getAttribute("name"));
				node.setAttribute("parentId", record.getAttribute("parentId"));

				
				DataTreeGrid.this.addData(node, new DSCallback(){
					//the callback to supress a error from smartclient
					public void execute(DSResponse response, Object rawData, DSRequest request)
					{
						TreeNode parent=DataTreeGrid.this.getTree().getParent(record);
						DataTreeGrid.this.getTree().reloadChildren(parent);
						
					}});

			}
		});
		copyItem.setEnableIfCondition(new MenuItemIfFunction()
		{

			public boolean execute(Canvas target, Menu menu, MenuItem item)
			{
				TreeNode node = (TreeNode) DataTreeGrid.this.getRecord(DataTreeGrid.this.getEventRow());
				return !node.getAttributeAsString("id").equals(String.valueOf(dataNodeID));
				
			}
		});


		// -----------------------new folder Item
		final DSCallback dsCallback = new DSCallback()
		{

			public void execute(DSResponse response, Object rawData, DSRequest request)
			{
				if (response.getStatus() == RPCResponse.STATUS_FAILURE)
				{
					return;
				}
				ListGridRecord[] records = (ListGridRecord[]) response.getData();
				TreeNode newNode = (TreeNode) records[0];
				Tree tree = DataTreeGrid.this.getTree();
				TreeNode parentNode = tree.findById(newNode.getAttribute("parentId"));
				if (parentNode != null)
				{
					tree.openFolder(parentNode);
					DataTreeGrid.this.startEditing(DataTreeGrid.this.getRecordIndex(records[0]), 0, false);
				}
			}
		};

		folderItem.addClickHandler(new ClickHandler()
		{

			public void onClick(MenuItemClickEvent event)
			{
				Tree tree = DataTreeGrid.this.getTree();
				TreeNode treeNode = (TreeNode) DataTreeGrid.this.getSelectedRecord();
				if (!treeNode.getAttributeAsBoolean("folder"))
				{
					treeNode = DataTreeGrid.this.getTree().getParent(treeNode);
				}
				TreeNode newNode = new TreeNode();
				newNode.setAttribute("name", "NewFolder");
				newNode.setAttribute("servername", "NewFolder");
				newNode.setAttribute("parentId", treeNode.getAttribute("id"));
				newNode.setAttribute("folder", true);
				newNode.setAttribute("_appnewdir", true);
				DataTreeGrid.this.addData(newNode, dsCallback);
			}
		});
		folderItem.setEnableIfCondition(new MenuItemIfFunction()
		{

			public boolean execute(Canvas target, Menu menu, MenuItem item)
			{
				TreeNode node = (TreeNode) DataTreeGrid.this.getRecord(DataTreeGrid.this.getEventRow());
				return node.getAttributeAsBoolean("folder");
			}
		});


		// --------------reload
		reloadItem.addClickHandler(new ClickHandler()
		{

			public void onClick(MenuItemClickEvent event)
			{
				TreeNode treeNode = (TreeNode) DataTreeGrid.this.getSelectedRecord();
				if (!treeNode.getAttributeAsBoolean("folder"))
				{
					treeNode = DataTreeGrid.this.getTree().getParent(treeNode);
				}
				DataTreeGrid.this.getTree().reloadChildren(treeNode);
			}
		});
		reloadItem.setEnableIfCondition(new MenuItemIfFunction()
		{

			public boolean execute(Canvas target, Menu menu, MenuItem item)
			{
				TreeNode node = (TreeNode) DataTreeGrid.this.getRecord(DataTreeGrid.this.getEventRow());
				return node.getAttributeAsBoolean("folder");
			}
		});

		// -----------------upload
		uploadItem.addClickHandler(new ClickHandler()
		{

			public void onClick(MenuItemClickEvent event)
			{
				Tree tree = DataTreeGrid.this.getTree();
				TreeNode treeNode = (TreeNode) DataTreeGrid.this.getSelectedRecord();
				if (!treeNode.getAttributeAsBoolean("folder"))
				{
					treeNode = tree.getParent(treeNode);
				}
				String path = tree.getPath(treeNode);
				UploadWindow up = StaticHolder.getUploadWindow();
				up.myShowUp(treeNode.getAttributeAsString("id"), DataTreeDataSource.translatePath(path));

			}
		});
		uploadItem.setEnableIfCondition(new MenuItemIfFunction()
		{

			public boolean execute(Canvas target, Menu menu, MenuItem item)
			{
				TreeNode node = (TreeNode) DataTreeGrid.this.getRecord(DataTreeGrid.this.getEventRow());
				return node.getAttributeAsBoolean("folder");
			}
		});

		// -----------view
		viewItem.addClickHandler(new ClickHandler()
		{

			public void onClick(MenuItemClickEvent event)
			{

				TreeNode treeNode = (TreeNode) DataTreeGrid.this.getSelectedRecord();
				if (treeNode.getAttributeAsBoolean("folder"))
				{
					return;
				}
				String href = treeNode.getAttributeAsString("href");
				if (href != null)
				{
					Util.open(href);
				}
			}
		});
		viewItem.setEnableIfCondition(new MenuItemIfFunction()
		{

			public boolean execute(Canvas target, Menu menu, MenuItem item)
			{
				TreeNode node = (TreeNode) DataTreeGrid.this.getRecord(DataTreeGrid.this.getEventRow());
				return !node.getAttributeAsBoolean("folder");
			}
		});

		// --------------zip item
		zipItem.addClickHandler(new ClickHandler()
		{

			public void onClick(MenuItemClickEvent event)
			{

				TreeNode treeNode = (TreeNode) DataTreeGrid.this.getSelectedRecord();
				if (treeNode.getAttributeAsBoolean("folder"))
				{
					String href = treeNode.getAttributeAsString("href");
					Util.open(href+".zip?zip=true");
					return;
				}
			}
		});
		zipItem.setEnableIfCondition(new MenuItemIfFunction()
		{

			public boolean execute(Canvas target, Menu menu, MenuItem item)
			{
				TreeNode node = (TreeNode) DataTreeGrid.this.getRecord(DataTreeGrid.this.getEventRow());
				return node.getAttributeAsBoolean("folder");
			}
		});

		if (viewState == ViewState.USER || viewState == ViewState.JOB_TRANSFER)
		{
			menu.setItems(reloadItem, renameItem, deleteItem, copyItem, folderItem, uploadItem, viewItem, zipItem);
		} else
		{
			menu.setItems(reloadItem);
		}
		setContextMenu(menu);
		
	}

}
